package com.bodystm.algorithm;
/**
 * 血氧和血压通用的中值滤波算法
 * @author ehl
 *
 */
public class MedfilterBO {
	private static int LEN1=404; //356*0.8/2
	private static int CHANCOUNT=4;

	double x3BO[][] = new double[CHANCOUNT][2 * LEN1 + 1];
	double px3BO[][] = new double[CHANCOUNT][2 * LEN1 + 1];
	int icount3BO[] =new int[CHANCOUNT];

	void qSortBO(double[] x, int low, int high)
	{
		int  i, j;
		double s;
		if (low < high)
		{
			i = low;
			j = high;
			s = x[i];
			while (i < j)
			{
				while (i < j && x[j] > s) j--; /* ´ÓÓÒÏò×óÕÒµÚÒ»¸öÐ¡ÓÚxµÄÊý */
				if (i < j) x[i++] = x[j];
				while (i < j && x[i] < s) i++; /* ´Ó×óÏòÓÒÕÒµÚÒ»¸ö´óÓÚxµÄÊý */
				if (i < j) x[j--] = x[i];
			}
			x[i] = s;
	        qSortBO(x, low, i - 1); /* µÝ¹éµ÷ÓÃ */
	        qSortBO(x, i + 1, high);
		}
	}

	int iBinSearchBO(double[] sSource, int l, int h, double key)
	{
		int low = l, high = h, mid;
		while (low <= high)
		{
			mid = (low + high) / 2;//»ñÈ¡ÖÐ¼äµÄÎ»ÖÃ

			if (sSource[mid] > key)
				high = mid - 1; //Èç¹û±Èkey´ó£¬ÔòÍùµÍµÄÎ»ÖÃ²éÕÒ
			else if (sSource[mid] < key)
				low = mid + 1;  //Èç¹û±ÈkeyÐ¡£¬ÔòÍù¸ßµÄÎ»ÖÃ²éÕÒ
			else
				return mid; //ÕÒµ½Ôò·µ»ØÏàÓ¦µÄÎ»ÖÃ
		}
		return high;
	}

	//*******************************Ö÷º¯Êý******************************************

	public double MedFilterBO(double x, int chanId)
	{
		//µÚÒ»´ÎÖÐÖµÂË²¨
		int length = 0, temp = 0;
		double out = 0;
		int ppp = 0;
		int index = 0;
		double medianvalue1, medianvalue2;
		int ib, in;

	    if (icount3BO[chanId] >= 2 * (2 * LEN1 + 1))
	        icount3BO[chanId] -= (2 * LEN1 + 1);

	    if (icount3BO[chanId] < LEN1 + 1)
		{
	        x3BO[chanId][icount3BO[chanId]] = x;
	        px3BO[chanId][icount3BO[chanId]] = x;
	        icount3BO[chanId]++;
	        if (icount3BO[chanId] == LEN1 + 1)
			{
	            qSortBO(x3BO[chanId], 0, LEN1);
				length = LEN1 + 1;
				if (length % 2 == 1)
				{
					index = (length + 1) / 2;
	                out = x3BO[chanId][index - 1];
				}
				else
				{
					index = length / 2;
	                medianvalue1 = x3BO[chanId][index - 1];
	                medianvalue2 = x3BO[chanId][index];
					out = (medianvalue1 + medianvalue2) / 2;
				}
			}
		}
	    else if (icount3BO[chanId] < 2 * LEN1 + 1)
		{
	        length = icount3BO[chanId] + 1;
	        in = iBinSearchBO(x3BO[chanId], 0, icount3BO[chanId] - 1, x);
	        ib = icount3BO[chanId];
			++in;
			while (in < ib)
			{
	            x3BO[chanId][ib] = x3BO[chanId][ib - 1];
				ib--;
			}
	        x3BO[chanId][in] = x;

			if (length % 2 == 1)
			{
				index = (length + 1) / 2;
	            out = x3BO[chanId][index - 1];
			}
			else
			{
				index = length / 2;
	            medianvalue1 = x3BO[chanId][index - 1];
	            medianvalue2 = x3BO[chanId][index];
				out = (medianvalue1 + medianvalue2) / 2;
			}
	        px3BO[chanId][icount3BO[chanId]] = x;
	        icount3BO[chanId]++;
		}
		else
		{
			length = 2 * LEN1 + 1;
	        temp = icount3BO[chanId];
			while (temp >= length)
				temp -= length;

	        ib = iBinSearchBO(x3BO[chanId], 0, length - 1, px3BO[chanId][temp]);
	        in = iBinSearchBO(x3BO[chanId], 0, length - 1, x);
			if (in < ib)
			{
				++in;
				while (in < ib)
				{
	                x3BO[chanId][ib] = x3BO[chanId][ib - 1];
					ib--;
				}
			}
			else
			{
				while (in > ib)
				{
	                x3BO[chanId][ib] = x3BO[chanId][ib + 1];
					ib++;
				}
			}
	        x3BO[chanId][in] = x;
	        px3BO[chanId][temp] = x;
	        icount3BO[chanId]++;
	        out = x3BO[chanId][LEN1];
	    }
	    return (px3BO[chanId][(temp<LEN1) ? (temp + LEN1 + 1) : (temp - LEN1)] - out);
	}

	double Sum(double[] pt,int startIndex, int len)
	{
	    double result = 0;
	    for (int i = 0; i < len; i++)
	    {
	        result += pt[startIndex+i];
	    }
	    return result;
	}

	/**
	* @describe: Motion and interference reject
	* @param: int type blood oxygen value, double type 256 length data stream after median filtering
	* @return: blood oxygen saturation level in percent
	* @author: Siyang Liang
	* @date: 2017/03/20
	*/
	double dSDPrevious = 0;//static
    int nSpO2Current,nSpO2;//static
    int nSpO2Previous = -1;
    int change = 0;
    /**
     * nSpO2 = MAReject(nSpO2, m_dIrf_AC+512, &nChangeBPMFalg);
     */
    public int nChangeBPMFalg=0;
    /**
     * nSpO2 = MAReject(nSpO2, m_dIrf_AC+512, &nChangeBPMFalg);
     */
    public int curIndex4dIred=0;
    //int *flag
	public int MAReject(int nCurrentBO, double[] dIred, int flag)//int[] flag
	{
	    double dTempSD, dSD, dSDCurrent;
	    double dMean;
	    double dTemp = 0;
	        
	    int i,nSpO2Out;

	    if(nCurrentBO > 100)
	    {
	        nCurrentBO = 100;
	    }
	    dMean = Sum(dIred,curIndex4dIred, 512)/512; // calculating the mean value
	    for (i = 0; i < 512; i++)
	    {
	        dTempSD = (dIred[i] - dMean)/512;
	        dTempSD = dTempSD*dTempSD;
	        dTemp += dTempSD;
	    }
	    dSD = Math.sqrt(dTemp); //calculating the standard deviation value
	    nSpO2Current = nCurrentBO;
	    nSpO2 = nCurrentBO;
	    // start of MA judge and rejection

	    if (Math.abs(nSpO2 - nSpO2Previous) > 3 && nSpO2Previous != -1 && dSDPrevious != 0)
	    {
	        if (Math.abs(1 - dSD / dSDPrevious) > 0.1 && nSpO2 - nSpO2Previous < 0) // this is the threshold of rejection sensitivity
	        {
	            nSpO2Out = nSpO2Previous;
	            nSpO2 = nSpO2Previous;
	            dSD = dSDPrevious;
	        }
	        else
	        {
	            if (nSpO2 - nSpO2Previous < -3)
	            {
	                nSpO2Out = nSpO2Previous;
	                nSpO2 = nSpO2Previous;
	                dSD = dSDPrevious;

	            }
	            else if (Math.abs(nSpO2 - nSpO2Previous) < 3)
	            {
	                nSpO2Out = nSpO2Current;
	                nSpO2 = nSpO2Current;

	            }
	            else
	            {
	                if (nSpO2Current > nSpO2Previous && change > 0)
	                {
	                    nSpO2Previous = nSpO2Current;
	                }
	                nSpO2Out = nSpO2Previous;
	                nSpO2 = nSpO2Previous;
	            }
	        }
	        change++;
	        flag = 1;
	        int tmp;
	        if (change > 1 && (tmp=Math.abs(nSpO2Current - nSpO2Previous)) > 5)
	        {

	            change = 0;
	            nSpO2 = nSpO2Current;
	            //dSD = dSDCurrent;

	        }
	        else
	        {

	        }
	    }
	    else if (nSpO2Previous == -1)
	    {
	        nSpO2Out = -1;
	        flag = 0;
	    }
	    else
	    {
	        nSpO2Out = nSpO2;
	        flag= 0;
	        change = 0;
	    }
	    dSDPrevious = dSD;
	    nSpO2Previous = nSpO2;
	    if(nCurrentBO != nSpO2Out)
	    {
	        //printf("----------------------------------------------------------curBO is %d      outBO is %d\n", nCurrentBO, nSpO2Out);
	    }
	    return nSpO2Out;

	}
}
